package com.lenovo.lcdm.dcm.controller;

import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.ExcelWriter;
import com.alibaba.excel.write.metadata.WriteSheet;
import com.alibaba.excel.write.metadata.fill.FillConfig;
import com.alibaba.fastjson2.JSON;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.lenovo.lcdm.common.enums.CommonMsgEnum;
import com.lenovo.lcdm.common.exception.BusinessException;
import com.lenovo.lcdm.common.model.ResponseVo;
import com.lenovo.lcdm.dcm.common.constant.CommonConstant;
import com.lenovo.lcdm.dcm.constant.DcmConstant;
import com.lenovo.lcdm.dcm.dto.DcmDownloadDto;
import com.lenovo.lcdm.dcm.dto.DcmLoadsheetDto;
import com.lenovo.lcdm.dcm.dto.DcmUploadResultDto;
import com.lenovo.lcdm.dcm.dto.DummyConfigurableModelDto;
import com.lenovo.lcdm.dcm.entity.DummyConfigurableModel;
import com.lenovo.lcdm.dcm.service.DcmBusinessConfigurationCategoryCService;
import com.lenovo.lcdm.dcm.service.DcmService;
import com.lenovo.lcdm.dcm.service.impl.FeaturesSheetWriteHandler;
import com.lenovo.lcdm.dcm.vo.DummyConfigurableModelVo;
import jakarta.servlet.http.HttpServletResponse;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import java.io.BufferedOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.stream.Collectors;

@Slf4j
@RestController
@RequestMapping("dcm")
public class DcmController {

    private final DcmService dcmService;

    private final DcmBusinessConfigurationCategoryCService businessConfigurationCategoryCService;

    @Autowired
    public DcmController(DcmService dcmService, DcmBusinessConfigurationCategoryCService businessConfigurationCategoryCService) {
        this.dcmService = dcmService;
        this.businessConfigurationCategoryCService = businessConfigurationCategoryCService;
    }

    /**
     * 创建dcm对象
     *
     * @return id
     */
    @PostMapping("createDcmInUI")
    public ResponseVo<Object> createDcmInUI(@RequestParam(name = "productName") String productName,
                                        @RequestParam(name = "geo") String geo,
                                        @RequestParam(name = "ctoNumbers") String ctoNumbers) {
        return ResponseVo.success(dcmService.createDcmInUI(productName, geo, ctoNumbers));
    }

    /**
     * 编辑dcm对象
     *
     * @param id dcmId
     * @return id
     */
    @PostMapping("checkout")
    public ResponseVo<DummyConfigurableModelVo> checkout(@RequestParam(name = "id") Integer id) {
        return ResponseVo.success(dcmService.checkout(id));
    }

    /**
     * 保存dcm对象
     *
     * @param dummyConfigurableModelDto dcm对象
     */
    @PostMapping("checkIn")
    public ResponseVo<Object> checkIn(@RequestBody DummyConfigurableModelDto dummyConfigurableModelDto) {
        dcmService.checkIn(dummyConfigurableModelDto);
        return ResponseVo.success();
    }

    @PostMapping("undoCheckout")
    public ResponseVo<Object> undoCheckout(@RequestParam(name = "ids") String ids) {
        dcmService.undoCheckout(ids);
        return ResponseVo.success();
    }

    /**
     * 编辑dcm对象
     *
     * @param keywords dcmName
     * @param pageNo   offset
     * @param pageSize size
     * @return 分页对象
     */

    @GetMapping("getDcms")
    public ResponseVo<IPage<DummyConfigurableModelVo>> getDcms(@RequestParam(name = "keywords", required = false) String keywords,
                                                               @RequestParam(name = "pageNo", required = false, defaultValue = "1") Integer pageNo,
                                                               @RequestParam(name = "pageSize", required = false, defaultValue = "10") Integer pageSize) {
        return ResponseVo.success(dcmService.getDcms(keywords, pageNo, pageSize));
    }

    @GetMapping("getDcmById")
    public ResponseVo<DummyConfigurableModelVo> getDcmById(@RequestParam(name = "id") Integer id) {
        return ResponseVo.success(dcmService.getDcmById(id));
    }

    @GetMapping("getDcmHistoryById")
    public ResponseVo<Object> getDcmHistoryById(@RequestParam(name = "id") Integer id) {
        return ResponseVo.success(dcmService.getDcmHistoryById(id));
    }

    @GetMapping("publicDcmByIds")
    public ResponseVo<Object> publicDcmByIds(@RequestParam(name = "ids") String ids) {
        return ResponseVo.success(dcmService.publicDcmByIds(ids));
    }

    @PostMapping("uploadDcmLoadsheet")
    public ResponseVo<List<DcmUploadResultDto>> uploadDcmLoadsheet(@RequestPart(name = "file") MultipartFile file) throws IOException {
        try {
            List<DcmUploadResultDto> data = dcmService.uploadDcmLoadsheet(file);
            return ResponseVo.success(data);
        } catch (IllegalArgumentException e) {
            if (e.getMessage().equals("No Sheet provided.")) {
                throw new BusinessException("Selected template is not 'Product Key Feature Template', please check.", CommonMsgEnum.FAIL.getCode());
            } else {
                throw new BusinessException(e.getMessage(), CommonMsgEnum.FAIL.getCode());
            }
        }
    }

    @PostMapping("refreshByIds")
    public ResponseVo<Object> refreshByIds(@RequestParam String ids) {
        return ResponseVo.success(dcmService.refreshByIds(ids));
    }

    @PostMapping("copy")
    public ResponseVo<Object> copy(@RequestParam Integer id, @RequestParam String portfolioName, @RequestParam String GEO) {
        return ResponseVo.success(dcmService.copyById(id, portfolioName, GEO));
    }

    @GetMapping("getLastVersionById")
    public ResponseVo<Object> getLastVersionById(@RequestParam(name = "id") Integer id) {
        return ResponseVo.success(dcmService.getLastVersionById(id));
    }

    @PostMapping("downloadDcmLoadsheet")
    public void downloadDcm(HttpServletResponse response, @RequestBody DcmDownloadDto dcmDownloadDto) throws Exception {
        //模板
        String templatePath = DcmConstant.DCM_KEY_FEATURES_PATH;
        //导出文件名
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyyMMddHHmmss");
        String fileName = templatePath.substring(templatePath.indexOf("/") + 1).replace(".", "_Template_" + simpleDateFormat.format(new Date()) + ".");
        InputStream input = null;
        OutputStream outputStream = null;
        try {
            List<DummyConfigurableModel> dcmList = dcmService.getDcmList(dcmDownloadDto.getIds());
            //检查GEO
            Set<String> geos = dcmList.stream().map(DummyConfigurableModel::getGeo).collect(Collectors.toSet());
            if (geos.size() > 1) {
                throw new BusinessException("Only same GEO product features can be download in one loadsheet, please check.", CommonMsgEnum.FAIL.getCode());
            }
            List<DcmLoadsheetDto> dtos = dcmService.getDcmLoadsheetDtos(dcmDownloadDto.getIds());
            String geo = (String) geos.toArray()[0];
            //查询category选项范围
            Set<String> categorySet = businessConfigurationCategoryCService.getDistinctCategory();

            input = PortfolioOfferingController.class.getClassLoader().getResourceAsStream(templatePath);
            outputStream = new BufferedOutputStream(response.getOutputStream());
            response.setContentType(CommonConstant.CONTENT_TYPE_XLSX);
            response.setCharacterEncoding(CommonConstant.CHARACTER_ENCODING_UTF8);
            response.setHeader("Content-disposition", "attachment;filename=" + fileName);
            try (ExcelWriter excelWriter = EasyExcel.write(outputStream).registerWriteHandler(new FeaturesSheetWriteHandler(categorySet)).withTemplate(input).build()) {
                WriteSheet writeSheet = EasyExcel.writerSheet(DcmConstant.SHEET_NAME_FEATURES).build();
                // 这里注意 入参用了forceNewRow 代表在写入list的时候不管list下面有没有空行 都会创建一行，然后下面的数据往后移动。默认 是false，会直接使用下一行，如果没有则创建。
                // forceNewRow 如果设置了true,有个缺点 就是他会把所有的数据都放到内存了，所以慎用
                // 简单的说 如果你的模板有list,且list不是最后一行，下面还有数据需要填充 就必须设置 forceNewRow=true 但是这个就会把所有数据放到内存 会很耗内存
                FillConfig fillConfig = FillConfig.builder().forceNewRow(Boolean.TRUE).build();

                // 写入geo
                Map<String, String> map = new HashMap<String, String>();
                map.put("geo", geo);
                excelWriter.fill(map, writeSheet);

                // 直接写入数据
                excelWriter.fill(dtos, fillConfig, writeSheet);
            }
        } catch (Exception e) {
            // 重置response
            response.reset();
            response.setContentType("application/json");
            response.setCharacterEncoding("utf-8");
            Map<String, Object> map = new HashMap<>();
            map.put("code", CommonMsgEnum.FAIL.getCode());
            map.put("message", e.getMessage());
            response.getWriter().println(JSON.toJSONString(map));
        } finally {
            try {
                if (input != null) {
                    input.close();
                }
                if (outputStream != null) {
                    outputStream.close();
                }
            } catch (IOException e) {
                log.error("关闭文件流失败，{}", e.getMessage());
            }
        }
    }

    @GetMapping("getFullCvs")
    public ResponseVo<Object> getFullCvs(@RequestParam(name = "id") Integer id, @RequestParam(name = "ctoNumber") String ctoNumber) {
        return ResponseVo.success(dcmService.getFullCvs(id, ctoNumber));
    }

    @GetMapping("model-test")
    public ResponseVo<Object> saveModelTest() {
        dcmService.testModel();
        return ResponseVo.success();
    }

    @GetMapping("getCategories")
    public ResponseVo<Object> getCategories() {
        return ResponseVo.success(businessConfigurationCategoryCService.getDistinctCategory());
    }

    @GetMapping("geos")
    public ResponseVo<Set<String>> getGeoList() {
        return ResponseVo.success(dcmService.getEditPermissionGeos());
    }

    @PostMapping("removeDcmById")
    public ResponseVo<Object> removeDcmById(@RequestParam Integer id) {
        dcmService.removeDcmById(id);
        return ResponseVo.success();
    }
}

